home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / ccdl151s.zip / SOURCE / GSTMT68.C < prev    next >
C/C++ Source or Header  |  1997-06-04  |  24KB  |  781 lines

  1. /*
  2.  * 68K/386 32-bit C compiler.
  3.  *
  4.  * copyright (c) 1997, David Lindauer
  5.  * 
  6.  * This compiler is intended for educational use.  It may not be used
  7.  * for profit without the express written consent of the author.
  8.  *
  9.  * It may be freely redistributed, as long as this notice remains intact
  10.  * and either the original sources or derived sources 
  11.  * are distributed along with any executables derived from the originals.
  12.  *
  13.  * The author is not responsible for any damages that may arise from use
  14.  * of this software, either idirect or consequential.
  15.  *
  16.  * v1.35 March 1997
  17.  * David Lindauer, gclind01@starbase.spd.louisville.edu
  18.  *
  19.  * Credits to Mathew Brandt for original K&R C compiler
  20.  *
  21.  */
  22. #include        <stdio.h>
  23. #include        "expr.h"
  24. #include        "c.h"
  25. #include        "gen68.h"
  26. #include                 "diag.h"
  27.  
  28. extern long lc_maxauto;
  29. extern int linkreg;
  30. extern long framedepth;
  31. extern TYP              stdfunc;
  32. extern struct amode     push[], pop[];
  33. extern OCODE *peep_tail, *peep_head, *peep_insert;
  34. extern long stackdepth;
  35. extern SYM *currentfunc;
  36. extern int prm_cplusplus,prm_linkreg, prm_phiform, prm_68020, prm_68010;
  37. extern int prm_rel, prm_smallcode;
  38. extern long firstlabel, nextlabel;
  39. extern int global_flag;
  40. extern int save_mask, fsave_mask;
  41. extern TABLE gsyms;
  42.  
  43. static int     diddef;
  44. static int     breaklab;
  45. static int     contlab;
  46. static int     retlab;
  47. static long gswitchbottom, gswitchcount;
  48. static long gswitchtop;
  49.  
  50. void genstmtini(void)
  51. {
  52. }
  53. AMODE    *makedreg(int r)
  54. /*
  55.  *      make an address reference to a data register.
  56.  */
  57. {       AMODE    *ap;
  58.         ap = xalloc(sizeof(AMODE));
  59.         ap->mode = am_dreg;
  60.         ap->preg = r;
  61.         return ap;
  62. }
  63.  
  64. AMODE    *makeareg(int r)
  65. /*
  66.  *      make an address reference to an address register.
  67.  */
  68. {       AMODE    *ap;
  69.         ap = xalloc(sizeof(AMODE));
  70.         ap->mode = am_areg;
  71.         ap->preg = r;
  72.         return ap;
  73. }
  74.  
  75. AMODE    *makefreg(int r)
  76. /*
  77.  *      make an address reference to a data register.
  78.  */
  79. {       AMODE    *ap;
  80.         ap = xalloc(sizeof(AMODE));
  81.         ap->mode = am_freg;
  82.         ap->preg = r;
  83.         return ap;
  84. }
  85. AMODE    *make_mask(int mask, int reverse, int floatflag)
  86. /*
  87.  *      generate the mask address structure.
  88.  */
  89. {       AMODE    *ap;
  90.         ap = xalloc(sizeof(AMODE));
  91.                 if (floatflag)
  92.             ap->mode = am_fmask;
  93.         else
  94.                     ap->mode = am_mask;
  95.                 ap->preg = reverse;
  96.         ap->offset = (ENODE *)mask;
  97.         return ap;
  98. }
  99.  
  100. AMODE    *make_direct(int i)
  101. /*
  102.  *      make a direct reference to an immediate value.
  103.  */
  104. {       return make_offset(makenode(en_icon,(char *)i,0));
  105. }
  106.  
  107. AMODE    *make_strlab(char *s)
  108. /*
  109.  *      generate a direct reference to a string label.
  110.  */
  111. {       AMODE    *ap;
  112.         ap = xalloc(sizeof(AMODE));
  113.         ap->mode = am_direct;
  114.         ap->offset = makenode(en_nacon,s,0);
  115.         return ap;
  116. }
  117.  
  118. void genwhile(SNODE *stmt)
  119. /*
  120.  *      generate code to evaluate a while statement.
  121.  */
  122. {       int     lab1, lab2, lab3;
  123.         initstack();            /* initialize temp registers */
  124.         lab1 = contlab;         /* save old continue label */
  125.         contlab = nextlabel++;  /* new continue label */
  126.         if( stmt->s1 != 0 )      /* has block */
  127.                 {
  128.                         lab2 = breaklab;        /* save old break label */
  129.                 breaklab = nextlabel++;
  130.                                 gen_code(op_bra,0,make_label(contlab),0);
  131.                                 lab3 = nextlabel++;
  132.                                 gen_label(lab3);
  133.                 genstmt(stmt->s1);
  134.                                 gen_label(contlab);
  135.                 initstack();
  136.                                 if (stmt->lst)
  137.                                      gen_line(stmt->lst);
  138.                 truejp(stmt->exp,lab3);
  139.                 gen_label(breaklab);
  140.                 breaklab = lab2;        /* restore old break label */
  141.                 }
  142.         else                            /* no loop code */
  143.                 {
  144.                                 if (stmt->lst)
  145.                                      gen_line(stmt->lst);
  146.                         gen_label(contlab);
  147.                 initstack();
  148.                 truejp(stmt->exp,contlab);
  149.                 }
  150.         contlab = lab1;         /* restore old continue label */
  151. }
  152.  
  153. void gen_for(SNODE *stmt)
  154. /*
  155.  *      generate code to evaluate a for loop
  156.  */
  157. {       int     old_break, old_cont, exit_label, loop_label;
  158.         old_break = breaklab;
  159.         old_cont = contlab;
  160.         loop_label = nextlabel++;
  161.         exit_label = nextlabel++;
  162.         contlab = nextlabel++;
  163.         initstack();
  164.         if( stmt->label != 0 )
  165.                 gen_expr(stmt->label,F_ALL | F_NOVALUE
  166.                         ,natural_size(stmt->label));
  167.                 
  168.         gen_code(op_bra,0,make_label(contlab),0);
  169.         gen_label(loop_label);
  170.         if( stmt->s1 != 0 ) {
  171.                                 breaklab = exit_label;
  172.                 genstmt(stmt->s1);
  173.                 }
  174.         initstack();
  175.         if( stmt->s2 != 0 )
  176.                 gen_expr(stmt->s2,F_ALL | F_NOVALUE,natural_size(stmt->s2));
  177.                 gen_label(contlab);
  178.                 if (stmt->lst)
  179.                      gen_line(stmt->lst);
  180.         initstack();
  181.         if( stmt->exp != 0 )
  182.                 truejp(stmt->exp,loop_label);
  183.                 else
  184.                         gen_code(op_bra,0,make_label(loop_label),0);
  185.                 gen_label(exit_label);
  186.                  breaklab = old_break;
  187.                 contlab = old_cont;
  188. }
  189.  
  190. void genif(SNODE *stmt)
  191. /*
  192.  *      generate code to evaluate an if statement.
  193.  */
  194. {       int     lab1, lab2;
  195.         lab1 = nextlabel++;     /* else label */
  196.         lab2 = nextlabel++;     /* exit label */
  197.         initstack();            /* clear temps */
  198.         falsejp(stmt->exp,lab1);
  199.         genstmt(stmt->s1);
  200.         if( stmt->s2 != 0 )             /* else part exists */
  201.                 {
  202.                 gen_code(op_bra,0,make_label(lab2),0);
  203.                 gen_label(lab1);
  204.                 genstmt(stmt->s2);
  205.                 gen_label(lab2);
  206.                 }
  207.         else                            /* no else code */
  208.                 gen_label(lab1);
  209. }
  210.  
  211. void gendo(SNODE *stmt)
  212. /*
  213.  *      generate code for a do - while loop.
  214.  */
  215. {       int     oldcont, oldbreak;
  216.         oldcont = contlab;
  217.         oldbreak = breaklab;
  218.         contlab = nextlabel++;
  219.         gen_label(contlab);
  220.         if( stmt->s1 != 0 && stmt->s1->next != 0 )
  221.                 {
  222.                 breaklab = nextlabel++;
  223.                 genstmt(stmt->s1);      /* generate body */
  224.                 initstack();
  225.                 truejp(stmt->exp,contlab);
  226.                 gen_label(breaklab);
  227.                 }
  228.         else
  229.                 {
  230.                 genstmt(stmt->s1);
  231.                 initstack();
  232.                 truejp(stmt->exp,contlab);
  233.                 }
  234.         breaklab = oldbreak;
  235.         contlab = oldcont;
  236. }
  237. void gen_genword(SNODE *stmt)
  238. /*
  239.  * Generate data in the code stream
  240.  */
  241. {
  242.         gen_code(op_genword,2,make_immed((int)stmt->exp),0);
  243. }
  244. AMODE *set_symbol(char *name, int isproc)
  245. /*
  246.  *      generate a call to a library routine.
  247.  */
  248. {       SYM     *sp;
  249.         AMODE *result;
  250.         sp = gsearch(name);
  251.         if( sp == 0 )
  252.                 {
  253.                 ++global_flag;
  254.                 sp = xalloc(sizeof(SYM));
  255.                 sp->tp = &stdfunc;
  256.                 sp->name = name;
  257.                                 if (isproc)
  258.                     sp->storage_class = sc_externalfunc;
  259.                                 else
  260.                     sp->storage_class = sc_external;
  261.                                 sp->extflag = TRUE;
  262.                 insert(sp,&gsyms);
  263.                 --global_flag;
  264.                 }
  265.                 result = make_strlab(name);
  266.                 return result;                    
  267. }
  268. AMODE *flush_for_libcall()
  269. {
  270.         AMODE *result = temp_addr();
  271.         temp_addr();                    /* push any used addr temps */
  272.         freeop(result); freeop(result);
  273.         result = temp_data();
  274.         temp_data(); temp_data();      /* push any used data registers */
  275.         freeop(result); freeop(result); freeop(result);
  276. }
  277. AMODE *call_library(char *lib_name,int size)
  278. /*
  279.  *      generate a call to a library routine.
  280.  */
  281. {       
  282.         AMODE *result;
  283.                 result = set_symbol(lib_name,1);
  284.         gen_code(op_bsr,0,result,0);
  285.                 if (size)
  286.             gen_code(op_add,4,make_immed(size),makeareg(7));
  287.                 result = temp_data();
  288.                 if (result->preg != 0)
  289.             gen_code(op_move,4,makedreg(0),result);
  290.                 result->tempflag = TRUE;
  291.                 return result;                    
  292. }
  293.  
  294. int analyzeswitch(SNODE *stmt)
  295. /* 
  296.  * Decide whitch type of switch statement to use
  297.  */
  298. {
  299.     gswitchbottom = 0x7fffffff;
  300.     gswitchtop = -0x80000000;
  301.     gswitchcount = 0;
  302.     stmt = stmt->s1;
  303.     while (stmt) {
  304.         if (!stmt->s2) {
  305.             gswitchcount++;
  306.             if ((int)stmt->label < gswitchbottom)
  307.                 gswitchbottom = (int)stmt->label;
  308.             if ((int)stmt->label > gswitchtop)
  309.                 gswitchtop = (int)stmt->label;
  310.         }
  311.         stmt = stmt->next;
  312.     }
  313.     gswitchtop++;
  314.     if (gswitchcount == 0)
  315.         return(0);
  316.     if (gswitchcount > 3)
  317.         if (gswitchcount*10/(gswitchtop-gswitchbottom) >= 8)
  318.             return(1);
  319.     return(2);
  320. }
  321.         
  322. void bingen(int lower, int avg, int higher,AMODE *ap1, int deflab, int size, long *switchids, int *switchlabels, int *switchbinlabels)
  323. /*
  324.  * Recursively output the compare/jump tree for a type of binary search
  325.  * on the case value
  326.  */
  327. {
  328.     AMODE *ap2 = make_immed(switchids[avg]);
  329.     AMODE *ap3 = make_label(switchlabels[avg]);
  330.     if (switchbinlabels[avg] != -1)
  331.         gen_label(switchbinlabels[avg]);
  332.     gen_code(op_cmp,4,ap2,ap1);
  333.     gen_code(op_beq,0,ap3,0);
  334.     if (avg == lower) {
  335.         ap3 = make_label(deflab);
  336.         gen_code(op_bra,0,ap3,0);
  337.     }
  338.     else {
  339.         int avg1 = (lower + avg)/2;
  340.         int avg2 = (higher + avg+1)/2;
  341.         if (avg+1 < higher) 
  342.             ap3 = make_label(switchbinlabels[avg2]=nextlabel++);
  343.         else
  344.             ap3 = make_label(deflab);
  345.         if (size < 0)
  346.             gen_code(op_bgt,0,ap3,0);
  347.         else
  348.             gen_code(op_bhi,0,ap3,0);
  349.         bingen(lower,avg1,avg,ap1,deflab,size,switchids,switchlabels,switchbinlabels);
  350.         if (avg+1 < higher)
  351.             bingen(avg+1,avg2,higher,ap1,deflab,size,switchids,switchlabels,switchbinlabels);
  352.     }
  353. }
  354. void genbinaryswitch(SNODE *stmt, int deflab)
  355. /*
  356.  * Main routine for handling the binary switch setup
  357.  */
  358. {
  359.     int curlab, i=0,j,size = natural_size(stmt->exp);
  360.     AMODE *ap1;
  361.   long switchbottom=gswitchbottom, switchcount=gswitchcount;
  362.   long switchtop=gswitchtop;
  363.   int *switchlabels=0;
  364.   long *switchids=0;
  365.   int *switchbinlabels=0;
  366.     curlab = nextlabel++;
  367.   initstack();
  368.   ap1 = gen_expr(stmt->exp,F_DREG,4);
  369.     global_flag++;
  370.     switchlabels = xalloc((switchcount) * sizeof(int));
  371.     switchbinlabels = xalloc((switchcount) * sizeof(int));
  372.     switchids = xalloc((switchcount) * sizeof(long));
  373.     global_flag--;
  374.     stmt = stmt->s1;
  375.     while (stmt) {
  376.                 if( stmt->s2 )          /* default case ? */
  377.                         {
  378.                         stmt->label = (SNODE *) deflab;
  379.                                                 diddef = TRUE;
  380.                         }
  381.                 else
  382.                         {
  383.                                                 switchlabels[i] = curlab;
  384.                                                 switchbinlabels[i] = -1;
  385.                                                 switchids[i++] = (int)stmt->label;
  386.                                                 stmt->label = (SNODE *)curlab;
  387.                         }
  388.                 if( stmt->next != 0 )
  389.                         curlab = nextlabel++;
  390.                 stmt = stmt->next;
  391.                 }
  392.     for (i=0; i < switchcount; i++)
  393.         for (j=i+1; j < switchcount; j++)
  394.             if (switchids[j] < switchids[i]) {
  395.                 int temp = switchids[i];
  396.                 switchids[i] = switchids[j];
  397.                 switchids[j] = temp;
  398.                 temp = switchlabels[i];
  399.                 switchlabels[i] = switchlabels[j];
  400.                 switchlabels[j] = temp;
  401.             }
  402.     bingen(0,(switchcount)/2,switchcount,ap1,deflab,size,switchids,switchlabels,switchbinlabels);
  403. }
  404. void gencompactswitch(SNODE *stmt, int deflab)
  405. /*
  406.  * Generate a table lookup mechanism if the switch table isn't too sparse
  407.  */
  408. {       int             tablab,curlab,i;
  409.         AMODE    *ap,*ap1,*ap2,*ap3;
  410.               long switchbottom=gswitchbottom, switchcount=gswitchcount;
  411.               long switchtop=gswitchtop;
  412.               int *switchlabels=0;
  413.                 tablab = nextlabel++;
  414.         curlab = nextlabel++;
  415.         initstack();
  416.         ap = gen_expr(stmt->exp,F_DREG | F_VOL,4);
  417.                 initstack();
  418.                 if (switchbottom) {
  419.                     gen_code(op_sub,4,make_immed(switchbottom),ap);
  420.                     gen_code(op_blo,0,make_label(deflab),0);
  421.                 }
  422.                 gen_code(op_cmp,4,make_immed(switchtop-switchbottom),ap);
  423.                 gen_code(op_bhs,0,make_label(deflab),0);
  424.                 ap1= temp_addr();
  425.                 ap2 = xalloc(sizeof(AMODE));
  426.                 if (prm_rel) {
  427.                     ap2->preg = ap1->preg;
  428.                     ap2->mode = am_pcindx;
  429.                 }
  430.                 else {
  431.                     ap2->mode = am_adirect;
  432.                     if (prm_smallcode)
  433.                         ap2->preg = 2;
  434.                     else
  435.                         ap2->preg = 4;
  436.                 }
  437.                 ap2->offset = makenode(en_labcon,(char *)tablab,0);
  438.                 gen_code(op_lea,0,ap2,ap1);
  439.                 if (prm_rel || prm_smallcode)
  440.                     gen_code(op_asl,4,make_immed(1),ap);
  441.                 else
  442.                     gen_code(op_asl,4,make_immed(2),ap);
  443.                 if (prm_rel) {
  444.                     gen_code(op_add,4,ap,ap1);
  445.                     ap2->mode = am_ind;
  446.                     gen_code(op_add,2,ap2,ap1);
  447.                 }
  448.                 else {
  449.                     ap3->sreg = ap->preg;
  450.                     ap3->preg = ap1->preg;
  451.                     ap3->scale = 0;
  452.                     ap3->offset = makenode(en_icon,0,0);
  453.                     ap3->mode = am_baseindxdata;
  454.                     gen_code(op_move,4,ap3,ap1);
  455.                 }
  456.                 ap1->mode = am_ind;
  457.                 gen_code(op_jmp,0,ap1,0);
  458.  
  459.                 initstack();
  460.                 gen_label(tablab);
  461.         switchlabels = xalloc((switchtop-switchbottom) * sizeof(int));
  462.     for (i=switchbottom; i < switchtop; i++) {
  463.         switchlabels[i-switchbottom] = deflab;
  464.     }
  465.     stmt = stmt->s1;
  466.     while (stmt) {
  467.                 if( stmt->s2 )          /* default case ? */
  468.                         {
  469.                         stmt->label = (SNODE *)deflab;
  470.                                                 diddef = TRUE;
  471.                         }
  472.                 else
  473.                         {
  474.                                                 switchlabels[(int)stmt->label-switchbottom] = curlab;
  475.                                                 stmt->label = (SNODE *)curlab;
  476.                         }
  477.                 if( stmt->next != 0 )
  478.                         curlab = nextlabel++;
  479.                 stmt = stmt->next;
  480.                 }
  481.     for (i=0; i < switchtop-switchbottom; i++)
  482.         if (prm_smallcode || prm_rel)
  483.             gen_code(op_dcl,2,make_label(switchlabels[i]),0);
  484.         else
  485.             gen_code(op_dcl,4,make_label(switchlabels[i]),0);
  486. }
  487.  
  488. void gencase(SNODE *stmt)
  489. /*
  490.  *      generate all cases for a switch statement.
  491.  */
  492. {       while( stmt != 0 )
  493.                 {
  494.                 gen_label((int)stmt->label);
  495.                 if( stmt->s1 != 0 )
  496.                         {
  497.                         genstmt(stmt->s1);
  498.                         }
  499.                 stmt = stmt->next;
  500.                 }
  501. }
  502.  
  503. void genxswitch(SNODE *stmt)
  504. /*
  505.  *      analyze and generate best switch statement.
  506.  */
  507. {       int     oldbreak;
  508.     int olddiddef = diddef;
  509.     int deflab = nextlabel++;
  510.         oldbreak = breaklab;
  511.         breaklab = nextlabel++;
  512.                 diddef = FALSE;
  513.                 switch (analyzeswitch(stmt)) {
  514.               case 2:
  515.                         genbinaryswitch(stmt,deflab);
  516.                         break;
  517.                     case 1:
  518.                         gencompactswitch(stmt,deflab);
  519.                         break;
  520.                     case 0:
  521.                         if (stmt->s1)
  522.                             stmt->s1->label = (SNODE *) nextlabel++;
  523.                         break;
  524.                 }
  525.         gencase(stmt->s1);
  526.         gen_label(breaklab);
  527.                 if (!diddef)
  528.             gen_label(deflab);
  529.         breaklab = oldbreak;
  530.     diddef = olddiddef;
  531. }
  532.  
  533. void genreturn(SNODE *stmt,int flag)
  534. /*
  535.  *      generate a return statement.
  536.  */
  537. {       AMODE    *ap,*ap1,*ap2,*ap3;
  538.                 int size;
  539.         if( stmt != 0 && stmt->exp != 0 )
  540.         {
  541.                 initstack();
  542.                                 if (currentfunc->tp->btp && currentfunc->tp->btp->type != bt_void && (currentfunc->tp->btp->type == bt_struct || currentfunc->tp->btp->type == bt_union)) {
  543.                                     int lbl;
  544.                                     lbl = nextlabel++;
  545.                                     size = currentfunc->tp->btp->size;
  546.                     ap = gen_expr(stmt->exp,F_AREG | F_VOL,4);
  547.                                     ap2 = xalloc(sizeof(AMODE));
  548.                                     if (prm_linkreg && !currentfunc->intflag) {
  549.                                         if (currentfunc->pascaldefn && currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1) {
  550.                                             ap2->preg = linkreg;
  551.                                             ap2->mode = am_indx;
  552.                                             ap2->offset = makenode(en_icon,(char *)(currentfunc->tp->lst.head->value.i + ((currentfunc->tp->lst.head->tp->size +3) &0xFFFFFFFCL)),0);
  553.                                         }
  554.                                         else {
  555.                                             ap2->preg = linkreg;
  556.                                             ap2->mode = am_indx;
  557.                                             ap2->offset = makenode(en_icon,(char *)8,0);
  558.                                         }
  559.                                     }
  560.                                     else if ( prm_phiform || currentfunc->intflag) {
  561.                                         if (currentfunc->pascaldefn && currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1) {
  562.                                             ap2->preg = linkreg;
  563.                                             ap2->mode = am_indx;
  564.                                             ap2->offset = makenode(en_icon,(char *)(currentfunc->tp->lst.head->value.i + ((currentfunc->tp->lst.head->tp->size +3) &0xFFFFFFFCL)),0);
  565.                                         }
  566.                                         else {
  567.                                              ap2->preg = linkreg;
  568.                                             ap2->mode = am_ind;
  569.                                         }
  570.                                     }
  571.                                     else {
  572.                                         if (currentfunc->pascaldefn && currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1) {
  573.                                             ap2->preg = 7;
  574.                                             ap2->mode = am_indx;
  575.                                             ap2->offset = makenode(en_icon,(char *)(framedepth+stackdepth+currentfunc->tp->lst.head->value.i + ((currentfunc->tp->lst.head->tp->size+3) & 0xfffffffcL)),0);
  576.                                         }
  577.                                         else {
  578.                                             ap2->preg = 7;
  579.                                             ap2->mode = am_indx;
  580.                                             ap2->offset = makenode(en_icon,(char *)(framedepth+stackdepth),0);
  581.                                         }
  582.                                     }
  583.                                     ap3 = temp_addr();
  584.                                     ap1 = temp_data();
  585.                                     gen_code(op_move,4,ap2,ap3);
  586.                                     ap->mode = am_ainc;
  587.                                     ap3->mode = am_ainc;
  588.                                     gen_code(op_move,4,make_immed(size),ap1);
  589.                                     gen_label(lbl);
  590.                                     gen_code(op_move,1,ap,ap3);
  591.                                     gen_code(op_sub,4,make_immed(1),ap1);
  592.                                     gen_code(op_bne,0,make_label(lbl),0);
  593.                                     gen_code(op_move,4,ap2,makedreg(0));
  594.                                     freeop(ap1);
  595.                                     freeop(ap3);
  596.                                     freeop(ap);
  597.                                 }
  598.                                 else {
  599.                                     size = currentfunc->tp->btp->size;
  600.                     ap = gen_expr(stmt->exp,F_ALL,size);
  601.                                     if (size > 4) {
  602.                         if( ap->mode != am_freg || ap->preg != 0 )
  603.                             gen_codef(op_fmove,size,ap,makefreg(0));
  604.                                     }
  605.                     else
  606.                             if( ap->mode != am_dreg || ap->preg != 0 )
  607.                             gen_code(op_move,size,ap,makedreg(0));
  608.                                 }
  609.         }
  610.                 if (flag) {
  611.             if( retlab != -1 )
  612.                 gen_label(retlab);
  613.                     if ((!prm_linkreg || currentfunc->intflag) && (lc_maxauto))
  614.                         if (lc_maxauto > 8) {
  615.                             AMODE *ap = xalloc(sizeof(AMODE)); 
  616.                             ap->mode = am_indx;
  617.                             ap->offset = makenode(en_icon,(char *)lc_maxauto,0);
  618.                             ap->preg = 7;
  619.                   gen_code(op_lea,0,ap,makeareg(7));
  620.                         }
  621.                         else
  622.                  gen_code(op_add,4,make_immed(lc_maxauto),makeareg(7));
  623.           if( fsave_mask != 0 )
  624.             gen_code(op_fmovem,10,pop,make_mask(fsave_mask,1,1));
  625.           if( save_mask != 0 )
  626.             gen_code(op_movem,4,pop,make_mask(save_mask,1,0));
  627.                     if (prm_linkreg && !currentfunc->intflag && (currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1 || lc_maxauto)) {
  628.                         gen_code(op_unlk,0,makeareg(linkreg),0);
  629.                     }
  630.                     if (currentfunc->intflag)
  631.                gen_code(op_rte,0,0,0);
  632.                     else
  633.                         if (currentfunc->pascaldefn) {
  634.                             long retsize = 0;
  635.                             if (currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1) {
  636.                                 retsize = currentfunc->tp->lst.head->value.i + ((currentfunc->tp->lst.head->tp->size +3) & 0xfffffffcl);
  637.                                 if (prm_linkreg)
  638.                                     retsize -= 8;
  639.                             } 
  640.                             if (currentfunc->tp->btp && currentfunc->tp->btp->type != bt_void && (currentfunc->tp->btp->type == bt_struct || currentfunc->tp->btp->type == bt_union)) 
  641.                                 retsize +=4;
  642.                             if (retsize) {
  643.                                 if (prm_68020 || prm_68010)
  644.                                     gen_code(op_rtd,0,make_immed(retsize),0);
  645.                                 else {
  646.                                     ap = temp_addr();
  647.                                     freeop(ap);
  648.                                     gen_code(op_move,4,pop,ap);
  649.                                     if (retsize > 8) {
  650.                                         ap1 = xalloc(sizeof(AMODE));
  651.                                         ap1->mode = am_indx;
  652.                                         ap1->offset = makenode(en_icon,(char *)retsize,0);
  653.                                         ap1->preg = 7;
  654.                         gen_code(op_lea,0,ap1,makeareg(7));
  655.                                     }
  656.                                     else
  657.                         gen_code(op_add,4,make_immed(retsize),makeareg(7));
  658.                                     ap->mode = am_ind;
  659.                                     gen_code(op_jmp,0,ap,0);
  660.                                 }
  661.                                 return;
  662.                             }
  663.                         }
  664.                gen_code(op_rts,0,0,0);
  665.         }
  666.         else {
  667.                     if (retlab == -1)
  668.                         retlab = nextlabel++;
  669.           gen_code(op_bra,0,make_label(retlab),0);
  670.                 }
  671. }
  672.  
  673. void genstmt(SNODE *stmt)
  674. /*
  675.  *      genstmt will generate a statement and follow the next pointer
  676.  *      until the block is generated.
  677.  */
  678. {
  679.            while( stmt != 0 )
  680.                 {
  681.                 switch( stmt->stype )
  682.                         {
  683.                                                 case st_block:
  684.                                                                 genstmt(stmt->exp);
  685.                                                                 break;
  686.                         case st_label:
  687.                                 gen_label((int)stmt->label);
  688.                                 break;
  689.                         case st_goto:
  690.                                 gen_code(op_bra,0,make_label((int)stmt->label),0);
  691.                                 break;
  692.                         case st_expr:
  693.                                 initstack();
  694.                                 gen_expr(stmt->exp,F_ALL | F_NOVALUE,
  695.                                         natural_size(stmt->exp));
  696.                                 break;
  697.                         case st_return:
  698.                                 genreturn(stmt,0);
  699.                                 break;
  700.                         case st_if:
  701.                                 genif(stmt);
  702.                                 break;
  703.                         case st_while:
  704.                                 genwhile(stmt);
  705.                                 break;
  706.                         case st_do:
  707.                                 gendo(stmt);
  708.                                 break;
  709.                         case st_for:
  710.                                 gen_for(stmt);
  711.                                 break;
  712.                                                 case st_line:
  713.                                                                 gen_line(stmt);
  714.                                                                 break;
  715.                         case st_continue:
  716.                                 gen_code(op_bra,0,make_label(contlab),0);
  717.                                 break;
  718.                         case st_break:
  719.                                                                  gen_code(op_bra,0,make_label(breaklab),0);
  720.                                 break;
  721.                         case st_switch:
  722.                                 genxswitch(stmt);
  723.                                 break;
  724.                                                 case st__genword:
  725.                                                                 gen_genword(stmt);
  726.                                                                 break;
  727.                         default:
  728.                                 DIAG("unknown statement.");
  729.                                 break;
  730.                         }
  731.                 stmt = stmt->next;
  732.                 }
  733. }
  734. #ifdef CPLUSPLUS
  735. void scppinit(void)
  736. /*
  737.  * Call C++ reference variable and class initializers
  738.  */
  739. {
  740.     if (!strcmp(currentfunc->name,"_main")) {
  741.         AMODE *ap1,*ap2,*ap3,*ap4;
  742.         int lbl = nextlabel++;
  743.         initstack();
  744.         ap1 = temp_addr();
  745.         ap4 = xalloc(sizeof(AMODE));
  746.         ap4->preg = ap1->preg;
  747.         ap4->mode = am_ind;
  748.         ap2 = set_symbol("CPPSTART",0);
  749.         ap3 = set_symbol("CPPEND",0);
  750.         gen_code(op_lea,4,ap2,ap1);
  751.         gen_label(lbl);
  752.         gen_code(op_move,4,ap1,push);
  753.         gen_code(op_jsr,4,ap4,0);
  754.         gen_code(op_move,4,pop,ap1);
  755.         gen_code(op_add,4,make_immed(4),ap1);
  756.         gen_code(op_cmp,4,ap3,ap1);
  757.         gen_code(op_bhi,0,make_label(lbl),0);
  758.         freeop(ap1);
  759.     }
  760. }
  761. #endif
  762. void genfunc(SNODE *stmt)
  763. /*
  764.  *      generate a function body.
  765.  */
  766. {       retlab = contlab = breaklab = -1;
  767.                 stackdepth = 0;
  768.                 if (stmt->stype == st_line) {
  769.                     gen_line(stmt);
  770.                     stmt = stmt->next;
  771.                 }
  772.                 gen_codelab(currentfunc);  /* name of function */
  773.         opt1(stmt);            /* push args & Also loads link reg and subtracts SP */
  774. #ifdef CPLUSPLUS
  775.                 if (prm_cplusplus) {
  776.                     scppinit();
  777.                 }
  778. #endif
  779.         genstmt(stmt);
  780.         genreturn(0,1);
  781. }